1 package nl.toolforge.karma.console;
2
3 import nl.toolforge.karma.core.ErrorCode;
4 import nl.toolforge.karma.core.boot.LocationStore;
5 import nl.toolforge.karma.core.boot.ManifestStore;
6 import nl.toolforge.karma.core.boot.Store;
7 import nl.toolforge.karma.core.boot.WorkingContext;
8 import nl.toolforge.karma.core.boot.WorkingContextConfiguration;
9 import nl.toolforge.karma.core.boot.WorkingContextException;
10 import nl.toolforge.karma.core.location.PasswordScrambler;
11 import nl.toolforge.karma.core.vc.AuthenticationException;
12 import nl.toolforge.karma.core.vc.Authenticator;
13 import nl.toolforge.karma.core.vc.AuthenticatorKey;
14 import nl.toolforge.karma.core.vc.Authenticators;
15 import nl.toolforge.karma.core.vc.VersionControlSystem;
16 import nl.toolforge.karma.core.vc.cvsimpl.CVSRepository;
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19
20 import java.io.BufferedReader;
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.InputStreamReader;
24
25 /***
26 * Configures a <code>WorkingContext</code> and writes the configuration to <code>working-context.xml</code>. Required
27 * input will be asked through <code>System.in</code>.
28 *
29 * @author D.A. Smedes
30 * @version $Id: Configurator.java,v 1.6 2004/11/03 20:54:14 asmedes Exp $
31 */
32 final class Configurator {
33
34 private Log logger = LogFactory.getLog(Configurator.class);
35
36 private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
37
38 private WorkingContext context = null;
39 private WorkingContextConfiguration config = null;
40
41 /***
42 * Constructs a <code>Configurator</code> for <code>workingContext</code>.
43 *
44 * @param config The <code>WorkingContextConfiguration</code> to configure.
45 */
46 public Configurator(WorkingContext context, WorkingContextConfiguration config) {
47
48 this.config = config;
49 this.context = context;
50 }
51
52 /***
53 * Configures. When this method is finished, it returns silently. If something major has happened,
54 * <code>System.exit(1)</code> will have been called.
55 */
56 public void checkConfiguration() {
57
58 ManifestStore manifestStore = new ManifestStore(context);
59 LocationStore locationStore = new LocationStore(context);
60
61 boolean mChecked = false;
62
63 try {
64 checkMandatoryProperties();
65
66
67
68 context.configure(config);
69
70 mChecked = checkManifestStoreConfiguration(manifestStore);
71
72 } catch (IOException e) {
73 logger.error(e);
74 writeln("[ configurator ] ** Error configurating working context : " + e.getMessage());
75 System.exit(1);
76 }
77
78 if (mChecked) {
79
80 config.setProperty(WorkingContext.MANIFEST_STORE_MODULE, manifestStore.getModuleName());
81 config.setManifestStore(manifestStore);
82 try {
83
84 boolean lChecked = checkLocationStoreConfiguration(locationStore);
85
86 if (lChecked) {
87
88 config.setProperty(WorkingContext.LOCATION_STORE_MODULE, locationStore.getModuleName());
89 config.setLocationStore(locationStore);
90
91 } else {
92 logger.error("Could not configure location store.");
93 writeln("[ configurator ] ** Failed to configure the working context properly. Contact your administrator");
94 System.exit(1);
95 }
96 } catch (IOException e) {
97 logger.error(e);
98 writeln("[ configurator ] ** Error configurating working context : " + e.getMessage());
99 System.exit(1);
100 }
101 } else {
102 logger.error("Could not configure manifest store.");
103 writeln("[ configurator ] ** Failed to configure the working context properly. Contact your administrator");
104 System.exit(1);
105 }
106
107 try {
108
109 config.store();
110
111 } catch (WorkingContextException e) {
112 logger.error("[ configurator ] ** Failed to write configuration to `working-context.xml`.");
113 System.exit(1);
114 }
115
116 }
117
118 private void checkMandatoryProperties() throws IOException {
119
120 final String DEFAULT_PROJECT_BASE_DIR =
121 System.getProperty("user.home") + File.separator + "karma" + File.separator + context.getName();
122
123 boolean ok = false;
124
125 writeln("");
126
127 while (!ok) {
128
129 String newValue = null;
130
131 String projectBaseDir = config.getProperty(WorkingContext.PROJECT_BASE_DIRECTORY_PROPERTY);
132
133
134
135 if (projectBaseDir != null) {
136
137 if (new File(projectBaseDir).canWrite()) {
138 ok = true;
139 break;
140 } else {
141 write("[ configurator ] ** Error, '" + projectBaseDir + "' is write protected.");
142 }
143 }
144
145 projectBaseDir = (projectBaseDir == null ? DEFAULT_PROJECT_BASE_DIR : projectBaseDir);
146
147 write("[ configurator ] What is your project base directory (" + projectBaseDir + ") : ");
148 newValue = reader.readLine().trim();
149 if (!"".equals(newValue)) {
150 projectBaseDir = newValue;
151 }
152 config.setProperty(WorkingContext.PROJECT_BASE_DIRECTORY_PROPERTY, projectBaseDir);
153
154 ok = true;
155 }
156 }
157
158 /***
159 * Checks the ManifestStore configuration until it is correct.
160 *
161 * @throws IOException
162 */
163 private boolean checkManifestStoreConfiguration(ManifestStore mStore) throws IOException {
164
165 ErrorCode error = mStore.checkConfiguration();;
166
167 int retries = 0;
168 boolean quit = false;
169
170 while (error != null && !quit) {
171
172 if (error != null) {
173 retries++;
174 if (retries == 2) {
175 quit = true;
176 }
177 }
178
179 CVSRepository cvs = null;
180
181 try {
182 cvs = (CVSRepository) mStore.getLocation();
183 if (cvs == null) {
184 cvs = new CVSRepository("manifest-store");
185 }
186 } catch (ClassCastException c) {
187 write("[ configurator ] ** Sorry, only CVS is supported in this release.");
188 cvs = new CVSRepository("manifest-store");
189 }
190
191 cvs.setWorkingContext(context);
192
193 writeln("[ configurator ] Please configure the manifest-store !");
194
195 configureStore(cvs, mStore);
196
197
198
199 error = mStore.checkConfiguration();
200
201 if (error == null) {
202 break;
203 } else {
204 writeln("[ configurator ] ** Error in manifest store configuration : " + error.getErrorMessage());
205 }
206 }
207
208
209
210 return (error == null);
211 }
212
213
214 private boolean checkLocationStoreConfiguration(LocationStore lStore) throws IOException {
215
216 ErrorCode error = lStore.checkConfiguration();
217
218 int retries = 0;
219 boolean quit = false;
220
221 while (error != null && !quit) {
222
223 if (error != null) {
224 retries++;
225 if (retries == 2) {
226 quit = true;
227 }
228 }
229
230 CVSRepository cvs = null;
231
232 try {
233 cvs = (CVSRepository) lStore.getLocation();
234 if (cvs == null) {
235 cvs = new CVSRepository("location-store");
236 }
237 } catch (ClassCastException c) {
238 write("[ configurator ] ** Sorry, only CVS is supported in this release.");
239 cvs = new CVSRepository("location-store");
240 }
241
242 cvs.setWorkingContext(context);
243
244 writeln("[ configurator ] Please configure the location-store !");
245
246 configureStore(cvs, lStore);
247
248
249
250 error = lStore.checkConfiguration();
251
252 if (error == null) {
253 break;
254 } else {
255 writeln("[ configurator ] ** Error in location store configuration : " + error.getErrorMessage());
256 }
257 }
258
259
260
261 return (error == null);
262 }
263
264 private Store configureStore(CVSRepository cvs, Store store) throws IOException {
265
266
267
268 String newValue = "";
269
270
271
272 String protocol = cvs.getProtocol();
273 protocol = (protocol == null ? "pserver" : protocol);
274
275 while (!newValue.matches("pserver|local")) {
276 write("[ configurator ] What is your server protocol ? [ local | pserver ] (" + protocol + ") : ");
277 newValue = reader.readLine().trim();
278 newValue = ("".equals(newValue) ? protocol : newValue);
279 }
280 protocol = newValue;
281 cvs.setProtocol(protocol);
282
283 if (protocol.equals(CVSRepository.PSERVER)) {
284
285
286
287 String hostName = cvs.getHost();
288 hostName = (hostName == null ? "127.0.0.1" : hostName);
289
290 write("[ configurator ] What is your server's hostname or ip-adres ? (" + hostName + ") : ");
291 newValue = reader.readLine().trim();
292 if (!"".equals(newValue)) {
293 hostName = newValue;
294 }
295 cvs.setHost(hostName);
296
297
298
299 String port = (cvs.getPort() == -1 ? "2401" : "" + cvs.getPort());
300
301 write("[ configurator ] What is your server port ? (" + port + ") : ");
302 newValue = reader.readLine().trim();
303 if (!"".equals(newValue)) {
304 port = newValue;
305 }
306 cvs.setPort(("".equals(port) ? "2401" : port));
307 }
308
309
310
311 String repository = cvs.getRepository();
312 repository = (repository == null ? "/home/cvs" : repository);
313
314 write("[ configurator ] What is your server repository ? (" + repository + ") : ");
315 newValue = reader.readLine().trim();
316 if (!"".equals(newValue)) {
317 repository = newValue;
318 }
319 cvs.setRepository(repository);
320
321
322
323 String moduleName = store.getModuleName();
324
325 if (store instanceof ManifestStore) {
326 moduleName = (moduleName == null ? "manifests" : moduleName);
327 write("[ configurator ] What is the cvs module for the manifest store ? (" + moduleName + ") ");
328 } else {
329 moduleName = (moduleName == null ? "locations" : moduleName);
330 write("[ configurator ] What is the cvs module for the location store ? (" + moduleName + ") ");
331 }
332
333 newValue = reader.readLine().trim();
334 if (!"".equals(newValue)) {
335 moduleName = newValue;
336 }
337
338 String name = null;
339 while (moduleName.endsWith(File.separator)) {
340 moduleName.substring(0, name.length());
341 }
342 if (moduleName.lastIndexOf(File.separator) > 0) {
343 store.setModuleName(moduleName.substring(moduleName.lastIndexOf(File.separator) + 1));
344 cvs.setOffset(moduleName.substring(0, moduleName.lastIndexOf(File.separator)));
345 } else {
346 store.setModuleName(moduleName);
347 cvs.setOffset("");
348 }
349
350 try {
351 checkAuthentication(cvs);
352 } catch (ConfigurationException e) {
353 write("[ configurator ] Error : " + e.getMessage());
354 }
355
356
357
358 store.setLocation(cvs);
359
360 return store;
361 }
362
363
364 private void checkAuthentication(VersionControlSystem cvs) throws IOException, ConfigurationException {
365
366 Authenticator authenticator = null;
367 try {
368 authenticator = Authenticators.getAuthenticator(new AuthenticatorKey(context.getName(), cvs.getId()));
369 } catch (IllegalArgumentException e) {
370 throw new ConfigurationException("The file $HOME/.karma/authenticators.xml seems to be corrupt. Please remove it and try again, karma will generate it for you.", e);
371 } catch (AuthenticationException e) {
372 authenticator = new Authenticator();
373 }
374
375 authenticator.setWorkingContext(context.getName());
376 authenticator.setId(cvs.getId());
377
378 String userNameString = (authenticator.getUsername() == null ? "" : "(" + authenticator.getUsername() + ")");
379 String password = "";
380
381 String newValue = "";
382
383 while ("".equals(newValue)) {
384 write("[ configurator ] What is your username ? " + userNameString + " : ");
385 newValue = reader.readLine().trim();
386 newValue = ("".equals(newValue) ? authenticator.getUsername() : newValue);
387 authenticator.setUsername(newValue);
388 }
389
390 if (cvs.getProtocol().equals(CVSRepository.PSERVER)) {
391 writeln("[ configurator ] Password is required, but input is in text-mode. Be warned !");
392 write("[ configurator ] What is your password ? : ");
393 password = reader.readLine().trim();
394 password = ("".equals(password) ? "" : PasswordScrambler.scramble(password));
395 }
396
397 authenticator.setPassword(password);
398
399 try {
400 Authenticators.addAuthenticator(authenticator);
401 } catch (AuthenticationException e) {
402 throw new ConfigurationException("The file $HOME/.karma/authenticators.xml seems to be corrupt. Please remove it and try again, karma will generate it for you.", e);
403 }
404 }
405
406
407 private void writeln(String text) {
408 System.out.println(text);
409 }
410
411 private void write(String text) {
412 System.out.print(text);
413 }
414
415 }